了解 vue composition-api 原理

watch

我对 composition-api 中的 watch 的实现一直很好奇,它到底怎么知道我里面依赖了哪些变量?
例如下面的代码:
js
import {watchEffect, ref } from "vue" const msg = ref("后撤步!") watchEffect(()=>{ console.log(msg.value) }) setTimeout(()=>{ msg.value = "7777" },1000)
虽然用了这么久的 composition-api 但我从来都不明白 watchEffect 到底是怎么知道 cb 依赖了 msg 的
我自己猜想的方式有两种:
第一种是直接执行一遍 cb, msg 的 getter 内就能知道 cb 依赖了 msg,但 cb 内如果有 if 之类的逻辑就会漏掉一些变量的依赖
ts
const t = Date.now() watchEffect(()=>{ if(Date.now() - t > 500){ console.log(msg.value) // 永远不会被执行 } setTimeout(()=>{ console.log(msg.value) // 只会被执行一次 },10) }) setTimeout(()=>{ msg.value = "7777" },1000)
像这样的代码在 1000ms 后并不会打印 msg.value
另一种是获取 cb 的源码来进行分析,执行 cb.toString() 得到 ()=>{ console.log(msg) } 就可以看到里面依赖了 msg ,但如果将 cb 改一下
js
const a = ()=>{ console.log(msg) } const cb = ()=>{ a() }
这时候 cb.toString() 得到的是 ()=>{ a() } 还是没法知道里面依赖了 msg。
经过对 此处代码 的验证,可以猜测 vue 应该是采用的第一种方案,还是去看 vuejs/composition-api 的代码来研究一下吧

正文

watchEffect 的实现在 src/apis/watch.ts#L368 , 代码如下
ts
export function watchEffect( effect: WatchEffect, options?: WatchOptionsBase ): WatchStopHandle { const opts = getWatchEffectOption(options) const vm = getWatcherVM() return createWatcher(vm, effect, null, opts) }
这里没啥好看的,继续看 createWatcher : src/apis/watch.ts#L205 , 代码如下(精简了代码)
ts
function createWatcher( vm: ComponentInstance, source: WatchSource | WatchSource[] | WatchEffect, cb: WatchCallback | null, options: WatchOptions ): () => void { let running = false const getter = () => { // preventing the watch callback being call in the same execution if (running) { return } try { running = true ;(source as WatchEffect)(registerCleanup) } finally { running = false } } const watcher = createVueWatcher(vm, getter, noopFn, { deep: options.deep || false, sync: isSync, before: runCleanup, }) }
这里可以看到 16行的 (source as WatchEffect)(registerCleanup) 基本验证了猜测,继续看 createVueWatcher : src/apis/watch.ts#L170
https://www.typescriptlang.org/zh/play?#code/DYUwLgBAJiAOBcEBKIBmAeArgOwNbYHsB3bAPgG0BdCAXgioFgAoAYwOwGdIZYAZASzy0I2EEQgB1EAENcAWWmx0KDDnzEyAGggBlcOgBiOFmH7tSpABQBKZszABPWCGRp0AFVLCA3hABu0sCYIIjuEAC+zKjGpuwQAE5unpZ+odaIKh5e3swQeRCgkAFBLnR+ANy5+YlgmPHYEDlM+S0QHOD+gcEpaY1Vra3FwcJ+-QP5bJyQLABGAlzCPAJ4AHQA5uCWYAAW-By2zeMt-KgQlrPzYNZ9h0cDF3tgK6gE8QCi0izb5zO0XrM2A53fKRW6tcKaMYtDZFLogGyhG7AvI8FawTAcb47PZA5E1OoNIYgKEgsag0FRGJmBpsAC26LAICgWUsMMZ8UQNj+EHc6VcGE8SIm7AWROEbJA8RsY0mCzpDKZKmEiVQKThuJRcGerw+X0sPG5TSOhQgDwWdCWglw602PA1rROZwAhGarkLga7hKJxHowNKwUdLat2n6eNpXfaWqCjq6VtIoFBLFyaNkSfcCPTMIyoCoVmK6BKpZGQfbwvaDXRGGD8fVTRmFTm0MwKawRZBpMq0JYAMwHWXTDt0eVZplJ64p911zgEUArYAENaWaR59VjGsNZdE5sHZgh9z8WkgAhZseGsabuHCADsze0AEYAAxPg57g9Hk-J1Ngi8lYQADhlEUZxAOcF3OH9ggOCEIAAJifB8X3AABJbB2WKU8JyNfIIJAABqXDbwgbt4OsIA
未完待续